home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- **** ****
- **** atree.c for Windows ****
- **** ****
- **** atree release 2.7 ****
- **** Adaptive Logic Network (ALN) simulation library. ****
- **** Copyright (C) A. Dwelly, R. Manderscheid, M. Thomas, W.W. Armstrong ****
- **** 1991, 1992 ****
- **** ****
- **** License: ****
- **** A royalty-free license is granted for the use of this software for ****
- **** NON_COMMERCIAL PURPOSES ONLY. The software may be copied and/or ****
- **** modified provided this notice appears in its entirety and unchanged ****
- **** in all derived source programs. Persons modifying the code are ****
- **** requested to state the date, the changes made and who made them ****
- **** in the modification history. ****
- **** ****
- **** Patent License: ****
- **** The use of a digital circuit which transmits a signal indicating ****
- **** heuristic responsibility is protected by U. S. Patent 3,934,231 ****
- **** and others assigned to Dendronic Decisions Limited of Edmonton, ****
- **** W. W. Armstrong, President. A royalty-free license is granted ****
- **** by the company to use this patent for NON_COMMERCIAL PURPOSES ONLY ****
- **** to adapt logic trees using this program and its modifications. ****
- **** ****
- **** Limited Warranty: ****
- **** This software is provided "as is" without warranty of any kind, ****
- **** either expressed or implied, including, but not limited to, the ****
- **** implied warrantees of merchantability and fitness for a particular ****
- **** purpose. The entire risk as to the quality and performance of the ****
- **** program is with the user. Neither the authors, nor the ****
- **** University of Alberta, its officers, agents, servants or employees ****
- **** shall be liable or responsible in any way for any damage to ****
- **** property or direct personal or consequential injury of any nature ****
- **** whatsoever that may be suffered or sustained by any licensee, user ****
- **** or any other party as a consequence of the use or disposition of ****
- **** this software. ****
- **** ****
- **** Modification history: ****
- **** ****
- **** 90.05.09 Initial implementation, A.Dwelly ****
- **** 91.07.15 Release 2, Rolf Manderscheid ****
- **** Thanks to Allen Supynuk for turning my compression ****
- **** function into something readable. ****
- **** 91.10.30 0.0 and 1.0 replaced by code -> low and code -> high in ****
- **** atree_read_code to correct bug found by Monroe Thomas ****
- **** 92.27.02 Release 2.5, Monroe Thomas ****
- **** 92.03.07 Release 2.6, Monroe Thomas ****
- **** 92.01.08 Release 2.7, Monroe Thomas ****
- **** ****
- *****************************************************************************/
-
- /*****************************************************************************
- **** ****
- **** Include Files ****
- **** ****
- *****************************************************************************/
-
- #include <windows.h>
- #include <time.h>
-
- #ifndef __ATREE_H
- #include "atree.h"
- #endif
-
- extern int errno;
-
- /*****************************************************************************
- **** ****
- **** Constants ****
- **** ****
- *****************************************************************************/
-
- /* Node and leaf types */
-
- #define AND 0
- #define RIGHT 1
- #define LEFT 2
- #define OR 3
- #define LEAF 4
-
- #define LEFT_CHILD 0
- #define RIGHT_CHILD 1
-
- #define FALSE 0 /* As usual */
- #define TRUE 1
- #define UNEVALUATED 2 /* We complete the lattice of boolean functions */
- #define ATREE_ERROR 3
-
- /* Number of retries before an error in atree_rand_walk */
- #define MAX_RETRY 50
-
- /* Number of nodes/leaves to allocate in each call to malloc in get_node() */
- #define NEWMALLOC 1024
-
- /* Initialisation values */
-
- #define MAXSET 63
- #define ABOVEMID 32
- #define BELOWMID 31
- #define MINSET 0
-
-
- #define STACKSIZE 100 /* stack used in load_tree */
- #define LEAF_TOKEN 256
-
- #define CODING_HEADER_FORMAT "vectors=%i, width=%i, range=%f,%f\n"
- #define CODING_HEADER_ITEMS 4
-
- /*
- * Macros
- */
-
- /* This keeps lint quiet */
-
- #define Printf (void) printf
-
- /* Public and private procedures */
-
- #define public
- #define private static
-
- /* Infinite loops - for EVER */
-
- #define EVER (;;)
-
- /* Printing out the boolean lattice */
-
- #define PRINTBOOL(b) if (b == TRUE) {Printf("1");} else if (b == FALSE)\
- {Printf("0");} else if (b == UNEVALUATED) {Printf("U");} else \
- if (b == ATREE_ERROR) {Printf("E");} else {Printf("?");}
-
- /* Verbosity */
-
- #define VERBOSE(level,s) if (verbosity >= level) {s ;}
-
- /*
- * Types
- */
-
- typedef struct token_struct
- {
- int token;
- int bit_no;
- int complemented;
- } token_t; // struct is 6 bytes long
-
- /*
- * Preliminary Private Procedure Declarations
- */
-
- private LPATREE NEAR PASCAL get_node(int);
- private void NEAR PASCAL reclaim_node(LPATREE);
- private LPATREE NEAR PASCAL build_tree(LPINT, BOOL far *,int,int);
- private void NEAR PASCAL print_tree(LPATREE, FILE *, int, int);
- private BOOL NEAR PASCAL train(LPATREE, LPBIT_VEC, BOOL);
- private void NEAR PASCAL adapt(LPATREE, LPBIT_VEC, BOOL);
- private int NEAR PASCAL node_function(LPATREE);
- private void NEAR PASCAL compress_tree(LPATREE,LPFAST_TREE,LPFAST_TREE,LPFAST_TREE,LPINT);
- private int NEAR PASCAL count_leaves(LPATREE, int);
- private int NEAR PASCAL store_tree(LPATREE, FILE *);
- private int NEAR PASCAL get_token(FILE *, token_t far *);
-
-
- BOOL atree_quit_flag;
-
- HWND hStatusWnd;
-
- #pragma argsused
- long FAR PASCAL StatusDlgProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
- {
- if ((message == WM_COMMAND) && (wParam == IDCANCEL))
- {
- atree_quit_flag = TRUE;
- return(TRUE);
- }
- return(FALSE);
- }
-
- /*****************************************************************************
- *****************************************************************************
- **** ****
- **** Public Routines ****
- **** ****
- *****************************************************************************
- *****************************************************************************/
-
- /*****************************************************************************
- **** ****
- **** void FAR PASCAL Windows_Interrupt(cElapsed) ****
- **** ****
- **** DWORD cElapsed ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Allows Windows to access other applications that may be running ****
- **** A call to PeekMessage accomplishes this, and we process all calling ****
- **** window messages. Will only call PeekMessage if _cElapsed_ time ****
- **** has passed since the last call to Windows_Interrupt. ****
- **** ****
- *****************************************************************************/
-
- public void FAR PASCAL
- Windows_Interrupt(cElapsed)
-
- DWORD cElapsed;
-
- {
- static DWORD cTick = 0; /* number of ticks since first called */
- MSG msg; /* Windows message structure */
-
- if ((GetTickCount() - cTick) > cElapsed)
- {
- if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- cTick = GetTickCount();
- }
- }
-
-
- /*****************************************************************************
- **** ****
- **** void atree_init(hInstance, hWindow) ****
- **** ****
- **** HANDLE hInstance; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Initialises various global variables, and makes an initial call to ****
- **** the random number seed routine. ****
- *****************************************************************************/
-
- public void FAR PASCAL
- atree_init(hInstance, hWindow)
-
- HANDLE hInstance;
- HWND hWindow;
- {
- DWORD c;
-
- #pragma warn -nod
- randomize();
- #pragma warn .nod
- c = GetTickCount();
- (void) srand((int) c);
-
- c = GetWinFlags();
- if (!(c & WF_PMODE))
- {
- MessageBox(hWindow, "Atree software cannot run\nin Windows Real Mode!",
- "Not in Protected Mode!", MB_OK | MB_ICONSTOP);
- exit(0);
- }
-
- hStatusWnd = CreateDialog(hInstance, "atreeStatus", hWindow,
- MakeProcInstance((FARPROC)StatusDlgProc, hInstance));
-
- atree_quit_flag = FALSE;
- return;
- }
-
- /*****************************************************************************
- **** ****
- **** void atree_quit() ****
- **** ****
- **** sets the quit flag for use by other atree routines when an exit ****
- **** is desired ****
- *****************************************************************************/
-
- void FAR PASCAL
- atree_quit(void)
-
- {
- atree_quit_flag = TRUE;
- if (IsWindow(hStatusWnd))
- {
- DestroyWindow(hStatusWnd);
- }
- }
-
-
- /*****************************************************************************
- **** ****
- **** LPBIT_VEC atree_rand_walk(num,width,p) ****
- **** ****
- **** int num; ****
- **** int width; ****
- **** int p; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Creates an array of _num_ binary vectors, of _width_ bits where ****
- **** each is _p_ bits away from its neighbours in Hamming space. Each ****
- **** vector is unique. ****
- **** This routine returns NULL if it's unable to find enough vectors. ****
- *****************************************************************************/
-
- public LPBIT_VEC FAR PASCAL
- atree_rand_walk(num,width,p)
-
- int num;
- int width;
- int p;
-
- {
- /*
- * An initial vector is produced with random bits, and each subsequent
- * vector in the random walk just has _p_ bits flipped. In order to
- * guarantee that each vector is unique, it is checked against
- * a chained list of vectors of the same bit sum. If it is not already
- * in the chain it is appended to the end, or else the vector is discarded
- * and the process repeats itself.
- */
-
- LPBIT_VEC walk; /* An array of bit vectors */
- LPBIT_VEC pckd_vec; /* The packed unique ? vector */
- BOOL unique; /* Uniqueness flag set during testing */
- LPINT bit_sum_chain; /* Pointers to vectors of equivalent bit sums */
- LPINT next_vec; /* Chain array */
- LPSTR unpckd_vec; /* An unpacked vector */
- LPSTR this_vec; /* An unpacked vector */
- LPSTR mark_vec; /* TRUE where a bit has been flipped */
- int i;
- int j;
- int old_bit_sum; /* Last number of TRUE bits in vector */
- int bit_sum; /* Current number of TRUE bits in vector */
- int retrys; /* Number of attempts to find a unique vec */
- int victim; /* The bit just twiddled */
- int current_vec; /* Part of the chain */
-
- assert(num > 0);
- assert(width > 0);
- assert(p > 0 && p <= width);
-
- /* Assign space in memory */
-
- walk = (LPBIT_VEC ) farmalloc((unsigned) num * sizeof(bit_vec));
- MEMCHECK(walk);
- bit_sum_chain = (LPINT) farmalloc((unsigned) (width+1) * sizeof(int));
- MEMCHECK(bit_sum_chain);
- next_vec = (LPINT) farmalloc((unsigned) num * sizeof(int));
- MEMCHECK(next_vec);
- unpckd_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
- MEMCHECK(unpckd_vec);
- this_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
- MEMCHECK(this_vec);
- mark_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
- MEMCHECK(mark_vec);
-
- /* Clear bit_sum_chain */
-
- for (i = 0; i <= width; i++)
- {
- bit_sum_chain[i] = -1;
- }
-
- /* Clear next_vec */
-
- for (i = 0; i < num; i++)
- {
- next_vec[i] = -1;
- }
-
- /* Create initial vector and bit sum */
-
- old_bit_sum = 0;
- for (i = 0; i < width; i++)
- {
- // turn off compiler possibly incorrect assignment warning
- #pragma warn -pia
- if (unpckd_vec[i] = RANDOM(2))
- {
- old_bit_sum++;
- }
- // restore warning state
- #pragma warn .pia
- }
-
- walk[0] = *(bv_pack(unpckd_vec,width));
- bit_sum_chain[old_bit_sum] = 0;
-
- /* Random walk */
-
- for (i = 1; i < num; i++)
- {
- retrys = 0;
- unique = FALSE;
- while ((!unique) && (retrys < MAX_RETRY))
- {
- retrys++;
-
- /* Make a new vector */
-
- bit_sum = old_bit_sum;
- for (j = 0; j < width; j++)
- {
- this_vec[j] = unpckd_vec[j];
- mark_vec[j] = FALSE;
- }
-
- for (j = 0; j < p; j++)
- {
- do
- {
- victim = RANDOM(width);
- }
- while (mark_vec[victim]);
-
- mark_vec[victim] = TRUE;
- this_vec[victim] = !this_vec[victim];
- if (this_vec[victim] == FALSE)
- {
- bit_sum--;
- }
- else
- {
- bit_sum++;
- }
- }
-
- pckd_vec = bv_pack(this_vec,width);
-
- /* Compare it with the existing ones of equal bit length */
-
- if (bit_sum_chain[bit_sum] == -1)
- {
- /* There are no other vectors with this bit sum, so */
-
- unique = TRUE;
- walk[i] = *pckd_vec;
- bit_sum_chain[bit_sum] = i;
- next_vec[i] = -1;
- }
- else
- {
- current_vec = bit_sum_chain[bit_sum];
- for EVER /* We break out of here inside the loop */
- {
- if (bv_equal(&(walk[current_vec]),pckd_vec))
- {
- /* This vector already exists, unique = FALSE; */
- break;
- }
- else
- {
- if (next_vec[current_vec] == -1)
- {
- unique = TRUE;
- walk[i] = *pckd_vec;
- next_vec[current_vec] = i;
- next_vec[i] = -1;
- break;
- }
- else
- {
- current_vec = next_vec[current_vec];
- }
- }
- } /* for EVER */
- } /* if (bit_sum_chain...) */
- } /* while ((!unique... ))*/
-
- /*
- * If Unique is TRUE at this point, we have a unique
- * vector stored, we have to set up old_bit sum and unpckd_vec
- * for the next vector.
- * If unique is FALSE, we have tried to create a unique vector
- * MAX_RETRY times, and failed. We therefore signal an error.
- */
-
- if (unique)
- {
- for (j = 0; j < width; j++)
- {
- unpckd_vec[j] = this_vec[j];
- }
- old_bit_sum = bit_sum;
- }
- else
- {
- (void) farfree(walk);
- walk = NULL;
- break;
- }
- } /* for */
-
-
- /* Free space in memory */
-
- (void) farfree(bit_sum_chain);
- (void) farfree(next_vec);
- (void) farfree(unpckd_vec);
- (void) farfree(this_vec);
- (void) farfree(mark_vec);
-
- /* Return final vector */
-
- return(walk);
- }
-
- /*****************************************************************************
- **** ****
- **** LPATREE atree_create(numvars,leaves) ****
- **** ****
- **** int numvars; ****
- **** int leaves; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Creates an Armstrong tree with _leaves_ number of leaves connected ****
- **** to _numvars_ variables and their complements. The number of ****
- **** leaves should probably be at least twice _numvars_. ****
- **** The node functions and the connections are picked at random. ****
- **** ****
- *****************************************************************************/
-
- public LPATREE FAR PASCAL
- atree_create(numvars,leaves)
-
- int numvars;
- int leaves;
-
- {
- LPATREE tree;
- LPINT connection;
- BOOL far *complemented;
- BOOL comp;
- int i;
-
- assert(leaves > 0);
- assert(numvars > 0);
-
- /*
- * Create a list of bit inputs and shuffle, complemented inputs
- * are marked with a TRUE in the complemented array.
- */
-
- connection = (LPINT) farmalloc((unsigned) sizeof(int) * leaves);
- MEMCHECK(connection);
- complemented = (BOOL far *) farmalloc((unsigned) sizeof(BOOL) * leaves);
- MEMCHECK(complemented);
-
- comp = FALSE;
- for (i = 0; i < leaves; i++)
- {
- int numvarscount = i % numvars;
- if (numvarscount == 0)
- {
- comp = !comp;
- }
- connection[i] = numvarscount;
- complemented[i] = comp;
- }
-
- /* Shuffle */
-
- for (i = 0; i < leaves; i++)
- {
- int a;
- int b;
- int tmp;
-
- a = RANDOM(leaves);
- b = RANDOM(leaves);
- tmp = connection[a];
- connection[a] = connection[b];
- connection[b] = tmp;
- tmp = complemented[a];
- complemented[a] = complemented[b];
- complemented[b] = tmp;
- }
-
- tree = build_tree(connection, complemented, 0, leaves - 1);
-
- (void) farfree(connection);
- (void) farfree(complemented);
-
- return(tree);
- }
-
- /*****************************************************************************
- **** ****
- **** void atree_free(tree) ****
- **** ****
- **** LPATREE tree; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Returns memory occupied by _tree_ to the freelists. ****
- *****************************************************************************/
-
- public void FAR PASCAL
- atree_free(tree)
- LPATREE tree;
- {
- if (tree -> c_tag != LEAF)
- {
- atree_free(tree -> n_child_left);
- atree_free(tree -> n_child_right);
- }
- reclaim_node(tree);
- }
-
- /*****************************************************************************
- **** ****
- **** (int) atree_eval(tree,vec) ****
- **** ****
- **** LPATREE tree; ****
- **** LPBIT_VEC vec; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Applies the _tree_ to the bit vector _vec_ and returns the result, ****
- **** 1 for true, and 0 for false. ****
- *****************************************************************************/
-
- public BOOL FAR PASCAL
- atree_eval(tree,vec)
-
- LPATREE tree;
- LPBIT_VEC vec;
-
- {
- register BOOL result;
-
- switch (tree -> c_tag)
- {
- case AND:
- tree -> n_sig_right = UNEVALUATED;
- // turn off compiler possibly incorrect assignment warning
- #pragma warn -pia
- result = (tree -> n_sig_left =
- atree_eval(tree -> n_child_left, vec))
- && (tree -> n_sig_right =
- atree_eval(tree -> n_child_right, vec));
- // restore warning state
- #pragma warn .pia
- break;
-
- case RIGHT:
- tree -> n_sig_left = UNEVALUATED;
- result = (tree -> n_sig_right =
- atree_eval(tree -> n_child_right, vec));
- break;
-
- case LEFT:
- tree -> n_sig_right = UNEVALUATED;
- result = (tree -> n_sig_left =
- atree_eval(tree -> n_child_left, vec));
- break;
-
- case OR:
- tree -> n_sig_right = UNEVALUATED;
- // turn off compiler possibly incorrect assignment warning
- #pragma warn -pia
- result = (tree -> n_sig_left =
- atree_eval(tree -> n_child_left, vec))
- || (tree -> n_sig_right =
- atree_eval(tree -> n_child_right, vec));
- // restore warning state
- #pragma warn .pia
- break;
-
- case LEAF:
- result = bv_extract((int) tree -> l_bit_no, vec) != tree -> l_comp;
- break;
-
- }
-
- return(result);
- }
-
- /*****************************************************************************
- **** ****
- **** int atree_train(tree,tset,correct_result,bit_col,tset_size, ****
- **** no_correct,epochs,verbosity) ****
- **** ****
- **** LPATREE tree; ****
- **** LPBIT_VEC tset; ****
- **** LPBIT_VEC correct_result; ****
- **** int bit_col; ****
- **** int tset_size; ****
- **** int no_correct; ****
- **** int epochs; ****
- **** int verbosity; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This routine is the heart of the library. It takes an atree _tree_ ****
- **** to be trained, an array of input vectors _tset_, an array of ****
- **** vectors, _correct_result_ where each bit column holds a correct bit ****
- **** result for each vector in _tset_. [Note: Only a single vector is ****
- **** actually required here, but doing it this way make life convenient ****
- **** for training collections of trees for real numbers] An integer ****
- **** _bit_col_ denoting the column to be trained on. Another integer ****
- **** _test_size gives the size of both the _tset_ and _correct_result_ ****
- **** arrays. ****
- **** ****
- **** The _tree_ is trained until the number of vectors presented in ****
- **** _tset_ equals _epoch_ epochs, or the last presentation of the number****
- **** in an epoch had at least _no_correct_ presentations. ****
- **** The _verbosity_ is currently 0 or 1. ****
- **** The routine returns TRUE if it stopped because it succeeded ****
- **** _no_correct_ times. Returns FALSE if it did not achieve ****
- **** _no_correct_. Returns -1 if aborted. ****
- **** ****
- *****************************************************************************/
-
- #pragma argsused
-
- public int FAR PASCAL
- atree_train(tree,tset,correct_result,bit_col,tset_size,no_correct,
- epochs,verbosity)
-
- LPATREE tree;
- LPBIT_VEC tset;
- LPBIT_VEC correct_result;
- int bit_col;
- int tset_size;
- int no_correct;
- int epochs;
- int verbosity;
-
- {
- BOOL no_correct_flag = FALSE;
- LPINT vec_list;
- int i;
- int j;
- int cor_this_epoch;
- int vec_num;
- LPBIT_VEC vec;
- static BOOL show_status = TRUE;
-
- // verbosity parm has no effect in Windows version
-
- SetDlgItemText(hStatusWnd, IDD_ATREE_EPOCH, " ");
- SetDlgItemText(hStatusWnd, IDD_ATREE_CORRECT, " ");
- SetDlgItemText(hStatusWnd, IDD_ATREE_ACTUAL, " ");
- if(show_status)
- {
- ShowWindow(hStatusWnd, SW_SHOWNOACTIVATE);
- }
- UpdateWindow(hStatusWnd);
-
- vec_list = (LPINT) farmalloc((unsigned) sizeof(int) * tset_size);
- MEMCHECK(vec_list);
-
- for (i = 0; i < tset_size; i++)
- {
- vec_list[i] = i;
- }
-
- /* For the specified number of epochs */
-
- for (i = 0; i < epochs; i++)
- {
- cor_this_epoch = 0;
-
- SetDlgItemInt(hStatusWnd, IDD_ATREE_EPOCH, i, FALSE);
-
- /* Shuffle */
-
- for (j = 0; j < tset_size; j++)
- {
- int a;
- int b;
- int tmp;
-
- a = RANDOM(tset_size);
- do
- {
- b = RANDOM(tset_size);
- }
- while (a == b);
-
- tmp = vec_list[a];
- vec_list[a] = vec_list[b];
- vec_list[b] = tmp;
- }
-
- /* For the elements of the test set */
-
- for (j = 0; j < tset_size; j++)
- {
- if (atree_quit_flag)
- {
- atree_quit_flag = FALSE;
- (void) farfree(vec_list);
- show_status = ShowWindow(hStatusWnd, SW_HIDE);
- return(-1); // exit if requested
- }
-
- /* Pick a random vector */
-
- vec_num = vec_list[j];
- vec = tset + vec_num;
-
- /* Train the tree */
-
- if (train(tree,vec,bv_extract(bit_col,correct_result + vec_num)))
- {
- /* The tree succeeded */
-
- cor_this_epoch++;
- if (cor_this_epoch == no_correct)
- {
- no_correct_flag = TRUE;
- break; /* out of this epoch */
-
- } /* if (cor_this...) */
- } /* if (train..) */
- } /* for (j = ..) */
-
- SetDlgItemInt(hStatusWnd, IDD_ATREE_CORRECT, cor_this_epoch, FALSE);
-
- /* If no_correct_flag is TRUE here, its time to stop */
-
- if (no_correct_flag || i == epochs - 1)
- {
- int correct = 0;
-
- for (j = 0; j < tset_size; j++)
- {
- if (atree_eval(tree, tset + j)
- == bv_extract(bit_col, correct_result + j))
- {
- correct++;
- }
- }
-
- SetDlgItemInt(hStatusWnd, IDD_ATREE_ACTUAL, correct, FALSE);
-
- if (correct >= no_correct)
- {
- break; /* out of the epoch loop */
- }
- }
- } /* for (i = ...) */
-
- (void) farfree(vec_list);
- show_status = ShowWindow(hStatusWnd, SW_HIDE);
- return(no_correct_flag);
- }
-
- /*****************************************************************************
- **** ****
- **** (void) atree_print(tree,stream, verbosity) ****
- **** ****
- **** LPATREE tree; ****
- **** FILE *stream; ****
- **** int verbosity; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Prints out a tree for diagnostic and explanation purposes, the ****
- **** verbosity levels are 0 or above. ****
- *****************************************************************************/
-
- public void FAR PASCAL
- atree_print(tree, stream, verbosity)
-
- LPATREE tree;
- FILE *stream;
- int verbosity;
-
- {
- /*
- * This routine makes an immediate call to the private
- * print tree routine that takes an extra parameter
- * controlling the indentation.
- */
-
- print_tree(tree,stream,0,verbosity);
- }
-
-
- /*****************************************************************************
- **** ****
- **** LPATREE atree_fold(tree) ****
- **** ****
- **** LPATREE tree; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This function removes all LEFT and RIGHT nodes from _tree_ ****
- **** and returns a pointer to the resulting tree. ****
- **** ****
- *****************************************************************************/
-
- public LPATREE FAR PASCAL
- atree_fold(tree)
-
- LPATREE tree;
- {
- LPATREE folded_tree;
- int keep;
-
- switch (tree -> c_tag)
- {
- case LEAF:
- folded_tree = tree;
- break;
- case OR:
- case AND:
- tree -> n_child_left = atree_fold(tree -> n_child_left);
- tree -> n_child_right = atree_fold(tree -> n_child_right);
- folded_tree = tree;
- break;
- case LEFT:
- case RIGHT:
- keep = (tree -> c_tag == LEFT) ? LEFT_CHILD : RIGHT_CHILD;
- folded_tree = atree_fold(tree -> n_child[keep]);
- atree_free(tree -> n_child[!keep]);
- reclaim_node(tree);
- break;
- default:
- assert(0);
- }
-
- return(folded_tree);
- }
-
- /*****************************************************************************
- **** ****
- **** LPFAST_TREE atree_compress(tree) ****
- **** ****
- **** LPATREE tree; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This function converts an atree to a fast_tree. ****
- **** See the commentary for the private function ****
- **** compress_tree for more information. ****
- **** ****
- *****************************************************************************/
-
- public LPFAST_TREE FAR PASCAL
- atree_compress(tree)
- LPATREE tree;
- {
- LPFAST_TREE ftree;
- int leaf_num;
- int leaf_count = count_leaves(tree, TRUE);
-
- ftree = (LPFAST_TREE) farmalloc((unsigned) (leaf_count + 1) * sizeof(fast_tree));
- MEMCHECK(ftree);
-
- ftree[leaf_count].bit_no = -1; /* mark end */
- leaf_num = leaf_count - 1;
- compress_tree(tree, NULL, NULL, ftree, &leaf_num);
-
- return(ftree);
- }
-
- /*****************************************************************************
- **** ****
- **** BOOL atree_fast_eval(ftree, vec) ****
- **** ****
- **** LPFAST_TREE ftree; ****
- **** LPBIT_VEC vec; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This function is the fast_tree equivalent of atree_eval. ****
- **** ****
- *****************************************************************************/
-
- public BOOL FAR PASCAL
- atree_fast_eval(ftree, vec)
-
- register LPFAST_TREE ftree;
- LPBIT_VEC vec;
- {
- register int result;
-
- do
- {
- result = bv_extract(ftree -> bit_no, vec) != ftree -> comp;
- } while ((ftree = ftree -> next[result]) != NULL);
-
- return(result);
- }
-
-
- /*****************************************************************************
- **** ****
- **** void atree_fast_print(ftree, stream) ****
- **** ****
- **** LPFAST_TREE ftree; ****
- **** FILE *stream; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This function is outputs the fast tree _ftree_ to stream. ****
- **** ****
- *****************************************************************************/
-
- public void FAR PASCAL
- atree_fast_print(ftree, stream)
-
- LPFAST_TREE ftree;
- FILE *stream;
- {
- int i;
-
- for (i = 0; ftree[i].bit_no >= 0; i++)
- {
- fprintf(stream, "[%3d] bit=%s%d, next[0]=%d, next[1]=%d\n",
- i, ftree[i].comp ? "!" : "", ftree[i].bit_no,
- ftree[i].next[0] ? ftree[i].next[0] - ftree : -1,
- ftree[i].next[1] ? ftree[i].next[1] - ftree : -1);
- }
- }
-
-
- /*****************************************************************************
- **** ****
- **** int atree_set_code(code, low, high, count, width, dist) ****
- **** ****
- **** LPCODE_T code; ****
- **** double low; ****
- **** double high; ****
- **** int count; ****
- **** int width; ****
- **** int dist; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** This is the constructor for type code_t: _code_ is a far pointer ****
- **** to a code_t struct, _low_ and _high_ represent the real valued ****
- **** boundaries of the encoding, _count_ represents the number of ****
- **** vectors in the encoding, _width_ is the number of bits per vector, ****
- **** and _dist_ is the number of bits to change between successive ****
- **** vectors. ****
- **** Returns non-zero on FAILURE. ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_set_code(code, low, high, count, width, dist)
-
- LPCODE_T code;
- double low;
- double high;
- int count;
- int width;
- int dist;
- {
- int error = FALSE;
-
- assert(low < high);
- assert(count > 1);
- assert(width > 0);
- assert(dist > 0);
-
- code -> width = width;
- code -> low = low;
- code -> high = high;
-
- if (width == 1) /* boolean */
- {
- code -> vector = (LPBIT_VEC) farmalloc((unsigned) sizeof(bit_vec) * 2);
- MEMCHECK(code -> vector);
-
- // boolean 1
- code -> vector[0] = *bv_create(1);
- bv_set(0, &(code -> vector[0]), 0);
-
- // boolean 0
- code -> vector[1] = *bv_create(1);
- bv_set(0, &(code -> vector[1]), 1);
-
- code -> vector_count = 2;
- code -> step = high - low;
- }
- else
- {
- if ((code -> vector = atree_rand_walk(count, width, dist)) == NULL)
- {
- error = TRUE;
- }
- code -> vector_count = count;
- code -> step = (high - low) / (count - 1);
- }
- return(error);
- }
-
- /*****************************************************************************
- **** ****
- **** int atree_encode(x, code) ****
- **** ****
- **** double x; ****
- **** LPCODE_T code; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** returns the quantization level corresponding to the floating point ****
- **** value _x_. To get the bit vector, use the expression: ****
- **** ****
- **** code -> vector + atree_encode(x, code) ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_encode(x, code)
-
- double x;
- LPCODE_T code;
-
- {
- int index;
-
- if (code -> width == 1)
- {
- index = x > (code -> low + code -> high) / 2;
- }
- else if (x < code -> low)
- {
- // char szBuffer[100];
-
- // (void) sprintf(szBuffer,
- // "warning: atree_encode: argument out of range: %f\n", x);
-
- // MessageBox(GetDesktopWindow(), szBuffer, "atree_encode()",
- // MB_ICONHAND | MB_SYSTEMMODAL);
-
- index = 0;
- }
- else if (x > code -> high)
- {
- // char szBuffer[100];
-
- // (void) sprintf(szBuffer,
- // "warning: atree_encode: argument out of range: %f\n", x);
-
- // MessageBox(GetDesktopWindow(), szBuffer, "atree_encode()",
- // MB_ICONHAND | MB_SYSTEMMODAL);
-
- index = code -> vector_count - 1;
- }
- else
- {
- index = (int) floor(((x - code -> low) / code -> step) + 0.5);
- }
-
- return(index);
- }
-
-
- /*****************************************************************************
- **** ****
- **** int atree_decode(vec, code) ****
- **** ****
- **** LPBIT_VEC vec; ****
- **** LPCODE_T code; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** returns the quantization level corresponding to the bit vector ****
- **** _vec_. To get the corresponding floating point value, use the ****
- **** expression: ****
- **** ****
- **** code -> low + code -> step * atree_decode(vec, code) ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_decode(vec, code)
-
- LPBIT_VEC vec;
- LPCODE_T code;
-
- {
- int closest = 0;
-
- if (code -> width == 1) /* boolean */
- {
- closest = bv_extract(0, vec);
- }
- else
- {
- int i;
- int diff;
- int closest_bit_diff = code -> width;
-
- for (i = 0; i < code -> vector_count; i++)
- {
- if ((diff = bv_diff(vec, code -> vector + i)) < closest_bit_diff)
- {
- closest_bit_diff = diff;
- closest = i;
- }
- }
- }
- return(closest);
- }
-
-
- /*
- * atree I/O routines.
- */
-
- /*****************************************************************************
- **** ****
- **** int atree_tree(tree, filename) ****
- **** ****
- **** LPATREE tree; ****
- **** LPSTR filename; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Creates a file "filename", and stores the single tree pointed ****
- **** to by _tree_ in that file. ****
- **** Returns non-zero on failure. ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_store(tree, filename)
- LPATREE tree;
- LPSTR filename;
- {
- FILE *fp;
- char szName[80];
-
- lstrcpy(szName, filename); // fopen doesn't take LPSTR
-
- if ((fp = fopen(szName, "w")) == NULL)
- {
- return(errno);
- }
- atree_write(fp, tree);
- fclose(fp);
- return(0);
- }
-
-
- /*****************************************************************************
- **** ****
- **** LPATREE atree_load(filename) ****
- **** ****
- **** LPSTR filename; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Reads from file "filename", and returns the first tree contained ****
- **** in that file. ****
- **** ****
- *****************************************************************************/
-
- public LPATREE FAR PASCAL
- atree_load(filename)
-
- LPSTR filename;
-
- {
- FILE *fp;
- LPATREE tree;
- char szName[80];
-
- lstrcpy(szName, filename); // fopen doesn't take LPSTR
-
- if ((fp = fopen(szName, "r")) == NULL)
- {
- return(NULL);
- }
- tree = atree_read(fp);
- fclose(fp);
- return(tree);
- }
-
-
- /*****************************************************************************
- **** ****
- **** int atree_write(tree, stream) ****
- **** ****
- **** LPATREE tree; ****
- **** FILE *stream; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Stores a single _tree_ onto _stream_. ****
- **** Returns 0 for success, 1 on failure. ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_write(stream, tree)
-
- FILE *stream;
- LPATREE tree;
-
- {
- return store_tree(tree, stream) || fprintf(stream, ";\n") == EOF;
- }
-
-
- /*****************************************************************************
- **** ****
- **** LPATREE atree_read(stream) ****
- **** ****
- **** FILE *stream; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Reads tree stored in postfix notation. Valid symbols are: ****
- **** '&', '|', 'L', 'R' (AND, OR, LEFT, and RIGHT respectively), ****
- **** and numerals (representing bit numbers) optionally preceded ****
- **** by a '!' for negation. Returns NULL if any error or EOF is ****
- **** encountered. A file may store multiple trees, each tree is ****
- **** separated by a ';'. ****
- **** ****
- *****************************************************************************/
-
- public LPATREE FAR PASCAL
- atree_read(stream)
-
- FILE *stream;
-
- {
- token_t t;
- LPATREE node = NULL;
- int error = 0;
-
- LPATREE stack[STACKSIZE];
- int top = 0;
- #define ITEMS top
- #define PUSH(node) stack[top++] = (node)
- #define POP stack[--top]
-
- while ((error = get_token(stream, &t)) == 0)
- {
- if (t.token == EOF || t.token == ';')
- {
- break;
- }
-
- if (t.token == LEAF_TOKEN)
- {
- node = get_node(LEAF);
- node -> l_bit_no = t.bit_no;
- node -> l_comp = t.complemented;
- }
- else if (ITEMS < 2)
- {
- char szBuffer[80];
- (void) sprintf(szBuffer,
- "atree_read: too few arguments for %c, offset %ld\n",
- t.token, ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- break;
- }
- else
- {
- node = get_node(!LEAF);
- node -> n_cnt_left = (t.token == '|' || t.token == 'L')
- ? MAXSET : MINSET;
- node -> n_cnt_right = (t.token == '|' || t.token == 'R')
- ? MAXSET : MINSET;
- node -> c_tag = node_function(node);
- node -> n_sig_left = UNEVALUATED;
- node -> n_sig_right = UNEVALUATED;
- node -> n_child_right = POP;
- node -> n_child_left = POP;
- }
-
- if (ITEMS >= STACKSIZE)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer, "atree_read: stack overflow\n");
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- break;
- }
- else
- {
- PUSH(node);
- }
-
- } /* while */
-
- if (!error && ITEMS != 1)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer, "atree_read: unexpected ");
- if (t.token == EOF)
- {
- strcat(szBuffer, "EOF\n");
- }
- else
- {
- char szErr[80];
- (void) sprintf(szErr, "';', offset %ld\n", ftell(stream));
- strcat(szBuffer, szErr);
- }
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- }
-
- return(error ? NULL : node);
-
- #undef ITEMS
- #undef PUSH
- #undef POP
- }
-
- /*
- * code I/O routines
- */
-
- /*****************************************************************************
- **** ****
- **** int atree_write_code(stream, code) ****
- **** ****
- **** FILE *stream; ****
- **** LPCODE_T code; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Writes _code_ onto _stream_. ****
- **** Returns 0 for success, 1 on failure. ****
- **** ****
- *****************************************************************************/
-
- public int FAR PASCAL
- atree_write_code(stream, code)
-
- FILE *stream;
- LPCODE_T code;
-
- {
- int i;
- int error;
-
- error = fprintf(stream, CODING_HEADER_FORMAT,
- code -> vector_count, code -> width,
- code -> low, code -> high) == EOF;
-
- if (!error && code -> width > 1)
- {
- for (i = 0; i < code -> vector_count; i++)
- {
- if (bv_print(stream, code -> vector + i)
- || fprintf(stream, "\n") == EOF)
- {
- error = TRUE;
- break;
- }
- }
- }
- return(error);
- }
-
- /*****************************************************************************
- **** ****
- **** LPCODE_T atree_read_code(stream) ****
- **** ****
- **** FILE *stream; ****
- **** LPCODE_T code; ****
- **** ****
- **** Synopsis: ****
- **** ****
- **** Reads a _code_ from _stream_. ****
- **** Returns NULL if unsuccessful, returns _code_ if successful. ****
- **** ****
- *****************************************************************************/
-
-
- public LPCODE_T FAR PASCAL
- atree_read_code(stream, code)
-
- FILE *stream;
- LPCODE_T code;
-
- {
- char *buf;
- char *p;
- int i;
- int error = 0;
- int count, width;
- float high, low;
-
- if (fscanf(stream, CODING_HEADER_FORMAT,
- &count, &width, &low, &high) != CODING_HEADER_ITEMS)
- {
-
- char szBuffer[80];
- (void) sprintf(szBuffer, "atree_read_code: bad header, offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(NULL);
- }
- else if (count < 2)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: vector count too low, offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(NULL);
- }
- else if (high <= low)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: bad range, offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(NULL);
- }
- else if (width < 1)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: width must be at least 1, offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(NULL);
- }
-
- code -> vector_count = count;
- code -> width = width;
- code -> low = low;
- code -> high = high;
-
- if (width == 1)
- {
- atree_set_code(code, code -> low, /* low */
- code -> high, /* high */
- 2, /* count */
- 1, /* width */
- 1); /* distance */
- }
- else {
-
- code -> step = (code->high - code->low ) / (code -> vector_count - 1);
- code -> vector = (LPBIT_VEC)
- farmalloc((unsigned) sizeof(bit_vec) * code -> vector_count);
- MEMCHECK(code -> vector);
-
- buf = malloc((unsigned) code -> width + 2); /* room for \n and \0 */
- MEMCHECK(buf);
-
- for (i = 0; i < code -> vector_count; i++)
- {
- if (fgets(buf, code -> width + 2, stream) == NULL)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: read error on offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- break;
- }
-
- if (strlen(buf) != code -> width + 1
- || buf[code -> width] != '\n')
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: inconsistent vector length, offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- break;
- }
- else
- {
- buf[code -> width] = '\0'; /* remove \n */
- }
-
- if (strspn(buf, "01") != code -> width)
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "atree_read_code: garbage at offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- error++;
- break;
- }
-
- /*
- * prepare the vector for packing
- */
- for (p = buf; *p; p++)
- {
- *p -= '0';
- }
- code -> vector[i] = *(bv_pack(buf, code -> width));
- }
-
- (void) farfree(buf);
- if (error)
- {
- (void) farfree(code -> vector);
- code = NULL;
- }
- }
-
- return(code);
- }
-
-
- /*****************************************************************************
- *****************************************************************************
- **** ****
- **** Private Routines ****
- **** ****
- *****************************************************************************
- *****************************************************************************/
-
- /*
- * Free list management routines.
- */
- static LPATREE_LEAF free_leaf_list = NULL;
- static LPATREE_NODE free_node_list = NULL;
-
- #define get_free_list(type, free_list) { \
- int i; \
- type far *ptr = (type far *) farmalloc(sizeof(type) * NEWMALLOC); \
- MEMCHECK(ptr); \
- for (i = 0; i < NEWMALLOC - 1; i++) \
- ptr[i].next = &ptr[i + 1]; \
- ptr[NEWMALLOC - 1].next = free_list; \
- free_list = ptr; \
- }
-
- private LPATREE NEAR PASCAL
- get_node(tag)
-
- int tag;
-
- {
- LPATREE node;
-
- if (tag == LEAF)
- {
-
- /*
- * add to free_leaf_list if necessary.
- */
- if (free_leaf_list == NULL)
- {
- get_free_list(atree_leaf, free_leaf_list);
- }
-
- node = (LPATREE) free_leaf_list;
- free_leaf_list = free_leaf_list -> next;
- }
- else {
-
- /*
- * add to free_node_list if necessary.
- */
- if (free_node_list == NULL)
- {
- get_free_list(atree_node, free_node_list);
- }
-
- node = (LPATREE) free_node_list;
- free_node_list = free_node_list -> next;
- }
-
- node -> c_tag = tag;
- return(node);
- }
- #undef get_free_list
-
- /*
- * function reclaim_node()
- *
- * returns a node to its appropriate free_list
- */
-
- private void NEAR PASCAL
- reclaim_node(tree)
-
- LPATREE tree;
-
- {
- if (tree -> c_tag == LEAF)
- {
- tree -> leaf.next = free_leaf_list;
- free_leaf_list = (LPATREE_LEAF) tree;
- }
- else
- {
- tree -> node.next = free_node_list;
- free_node_list = (LPATREE_NODE) tree;
- }
- }
-
- /*
- * This routine recursively creates a random tree in the previously allocated
- * space starting at _tree_. It returns a pointer giving the next available
- * space for other calls.
- */
-
- private LPATREE NEAR PASCAL
- build_tree(connection, complemented, start, end)
-
- LPINT connection;
- BOOL far *complemented;
- int start;
- int end;
- {
- LPATREE node;
- int mid;
-
- /* Are we at a leaf? */
-
- if (start == end)
- {
- node = get_node(LEAF);
- node -> l_comp = complemented[start];
- node -> l_bit_no = connection[start];
- }
- else
- {
- /* This is a node. */
-
- node = get_node(AND);
- node -> c_tag = RANDOM(4);
-
- node -> n_cnt_left =
- (node -> c_tag == LEFT || node -> c_tag == OR) ? ABOVEMID : BELOWMID;
- node -> n_cnt_right =
- (node -> c_tag == RIGHT || node -> c_tag == OR) ? ABOVEMID : BELOWMID;
-
- /* clear the signals */
-
- node -> n_sig_right = UNEVALUATED;
- node -> n_sig_left = UNEVALUATED;
-
- /* Create descendants */
-
- mid = start + ((end - start)/2);
- node -> n_child_left
- = build_tree(connection, complemented, start, mid);
- node -> n_child_right
- = build_tree(connection, complemented, mid+1, end);
- }
- return(node);
- }
-
- /*
- * print_tree routine prints out an atree to the
- * file pointed to by _stream_
- */
-
- private void NEAR PASCAL
- print_tree(tree, stream, indent,verbosity)
-
- LPATREE tree;
- FILE *stream;
- int indent;
- int verbosity;
-
- {
- int i;
-
- if (tree -> c_tag != LEAF)
- {
- print_tree(tree -> n_child_right, stream, indent + 3, verbosity);
- }
-
- for (i = 0; i < indent; i++)
- {
- fprintf(stream, " ");
- }
-
- switch (tree -> c_tag)
- {
- case AND:
- fprintf(stream, "AND\n");
- break;
-
- case LEFT:
- fprintf(stream, "LEFT\n");
- break;
-
- case RIGHT:
- fprintf(stream, "RIGHT\n");
- break;
-
- case OR:
- fprintf(stream, "OR\n");
- break;
-
- case LEAF:
- fprintf(stream, "%sLEAF : %d\n",
- tree -> l_comp ? "~" : "", tree -> l_bit_no);
- break;
- }
-
- if (tree -> c_tag != LEAF)
- {
- print_tree(tree -> n_child_left, stream, indent + 3, verbosity);
- }
- }
-
- /*
- * This routine is actually responsible for the training of a tree for a
- * single input vector and desired result. If the tree gets the correct result
- * before the adaptation step occurs, the routine returns TRUE, otherwise,
- * false.
- */
-
- private BOOL NEAR PASCAL
- train(tree,vec,desired)
-
- LPATREE tree;
- LPBIT_VEC vec;
- BOOL desired;
-
- {
- BOOL correct;
-
- (void) atree_eval(tree,vec);
-
- adapt(tree,vec,desired);
-
- correct = atree_eval(tree,vec) == desired;
-
- if (!correct)
- {
- adapt(tree,vec,desired);
- }
-
- return(correct);
- }
-
- private void NEAR PASCAL
- adapt(tree,vec,desired)
-
- LPATREE tree;
- LPBIT_VEC vec;
- BOOL desired;
-
- {
- register int lres;
- register int rres;
- register int funct;
-
- /*
- * INCR and DECR implement bounded counters.
- */
- #define INCR(t) ((t) += ((t) < MAXSET))
- #define DECR(t) ((t) -= ((t) > MINSET))
-
- Windows_Interrupt(200);
-
- funct = tree -> c_tag;
-
- if (funct != LEAF)
- {
- /* If the left child is unevaluated, evaluate it */
-
- if ((lres = tree -> n_sig_left) == UNEVALUATED)
- {
- lres = atree_eval(tree -> n_child_left, vec);
- tree -> n_sig_left = lres;
- }
-
- /* If the right child is unevaluated, evaluate it */
-
- if ((rres = tree -> n_sig_right) == UNEVALUATED)
- {
- rres = atree_eval(tree -> n_child_right, vec);
- tree -> n_sig_right = rres;
- }
-
- /* Update the counters if needed */
-
- if (lres != rres)
- {
- if (lres)
- {
- (void) (desired ? INCR(tree -> n_cnt_left)
- : DECR(tree -> n_cnt_left));
- }
- else
- {
- (void) (desired ? INCR(tree -> n_cnt_right)
- : DECR(tree -> n_cnt_right));
- }
-
- /* has the node function changed? */
-
- tree -> c_tag = node_function(tree);
- funct = tree -> c_tag;
- }
-
- /* Assign responsibility to the left child */
-
- if (rres != desired || funct != (rres ? OR : AND))
- {
- adapt(tree -> n_child_left, vec, desired);
- }
-
- /* Assign responsibility to the right child */
-
- if (lres != desired || funct != (lres ? OR : AND))
- {
- adapt(tree -> n_child_right, vec, desired);
- }
- }
- #undef INCR
- #undef DECR
- }
-
- private int NEAR PASCAL
- node_function(tree)
-
- LPATREE tree;
-
- {
- int result;
-
- if ((tree -> n_cnt_left) >= ABOVEMID)
- {
- result = (tree -> n_cnt_right >= ABOVEMID) ? OR : LEFT;
- }
- else
- {
- result = (tree -> n_cnt_right >= ABOVEMID) ? RIGHT : AND;
- }
-
- return(result);
- }
-
- /*
- * compress_tree:
- * Alters the respresentation of an atree into a fast_tree.
- * A fast_tree is essentially a list of leaves; each leaf in the
- * list contains two pointers to subsequent leaves to evaluate,
- * one for each possible result of evaluating the current leaf.
- * A next pointer of NULL indicates that the evaluation is complete,
- * and the result of the tree is the result of the current leaf.
- *
- * parameters:
- * 'next_if_0' and 'next_if_1' each hold the location of the
- * next leaf to evaluate if the value of the current 'node' is
- * known. Of course, for the root these are NULL. 'leaf_num' is the
- * current index into 'ftree'; it starts at the last leaf.
- *
- * notes:
- * For non-leaf nodes, we traverse the children in reverse order
- * because we need to know the first leaf of a node's sibling (this
- * is the next leaf to evaluate if any children of 'node' produce a
- * tag value). If we go backwards, we know that this is the last
- * leaf we visited.
- */
-
- private void NEAR PASCAL
- compress_tree(node, next_if_0, next_if_1, ftree, leaf_num)
- LPATREE node;
- LPFAST_TREE next_if_0;
- LPFAST_TREE next_if_1;
- LPFAST_TREE ftree;
- LPINT leaf_num;
- {
-
- assert(*leaf_num >= 0);
- switch (node -> c_tag)
- {
- case LEAF:
- ftree[*leaf_num].next[0] = next_if_0;
- ftree[*leaf_num].next[1] = next_if_1;
- ftree[*leaf_num].bit_no = node -> l_bit_no;
- ftree[*leaf_num].comp = node -> l_comp;
- (*leaf_num)--;
- break;
- case AND:
- compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
- compress_tree(node->n_child[0], next_if_0, &ftree[*leaf_num+1], ftree,
- leaf_num);
- break;
- case OR:
- compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
- compress_tree(node->n_child[0], &ftree[*leaf_num+1], next_if_1, ftree,
- leaf_num);
- break;
- case LEFT:
- compress_tree(node->n_child[0], next_if_0, next_if_1, ftree, leaf_num);
- break;
- case RIGHT:
- compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
- break;
- default:
- assert(0);
- }
- }
-
- private int NEAR PASCAL
- count_leaves(tree, fold)
- LPATREE tree;
- int fold;
- {
- if (tree -> c_tag == LEAF)
- {
- return 1;
- }
- else if (fold && tree -> c_tag == LEFT)
- {
- return count_leaves(tree -> n_child_left, fold);
- }
- else if (fold && tree -> c_tag == RIGHT)
- {
- return count_leaves(tree -> n_child_right, fold);
- }
- else
- {
- return count_leaves(tree -> n_child_left, fold)
- + count_leaves(tree -> n_child_right, fold);
- }
- }
-
- /*
- * function: store_tree
- *
- * Stores _tree_ onto _stream_ using postfix notation.
- * Returns non-zero on failure.
- */
- private int NEAR PASCAL
- store_tree(tree, stream)
- LPATREE tree;
- FILE *stream;
- {
- int error;
-
- if (tree -> c_tag == LEAF)
- {
- error = fprintf(stream, "%s%d ",
- tree -> l_comp ? "!" : "", tree -> l_bit_no) == EOF;
- }
- else
- {
- error = store_tree(tree -> n_child_left, stream)
- || store_tree(tree -> n_child_right, stream);
- if (!error)
- {
- switch (tree -> c_tag)
- {
- case AND:
- error = fprintf(stream, "&") == EOF;
- break;
- case OR:
- error = fprintf(stream, "|") == EOF;
- break;
- case LEFT:
- error = fprintf(stream, "L") == EOF;
- break;
- case RIGHT:
- error = fprintf(stream, "R") == EOF;
- break;
- }
- }
- }
- return(error);
- }
-
- /*
- * function: get_token
- *
- * Reads the next token from _stream_ and returns information about it
- * in _t_. Returns 0 for success, 1 for failure.
- */
- private int NEAR PASCAL
- get_token(stream, t)
- FILE *stream;
- token_t far *t;
- {
- int c;
-
- /* skip white space */
- while (isspace(c = getc(stream)))
- ;
-
- t -> complemented = 0;
- switch (c)
- {
- case EOF:
- case 'L':
- case 'R':
- case '&':
- case '|':
- case ';':
- t -> token = c;
- break;
- case '!':
- t -> complemented = 1;
- /* skip white space */
- while (isspace(c = getc(stream)))
- ;
-
- if (!isdigit(c))
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "get_token: expecting digit after '!', offset %ld\n",
- ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "get_token()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(1);
- }
- /* FALLTHRU */
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- t -> token = LEAF_TOKEN;
- t -> bit_no = c - '0';
- while (isdigit(c = getc(stream)))
- {
- t -> bit_no = t -> bit_no * 10 + c - '0';
- }
- (void) ungetc(c, stream);
- break;
-
- default:
- {
- char szBuffer[80];
-
- (void) sprintf(szBuffer,
- "get_token: unexpected symbol: '%c', offset %ld\n",
- c, ftell(stream));
-
- MessageBox(GetDesktopWindow(), szBuffer, "get_token()",
- MB_ICONHAND | MB_SYSTEMMODAL);
-
- return(1);
- }
- }
-
- return(0);
- }
-